INTRO
Hi again everyone. This is my second effort at a tutorial, and I will make this very similar to the last one, but not quite so slow. Though it should be pretty easy to follow. Contact me for help at any time at karnak@apexmail.com.
INFO
The Proggie - Duelist's Crackme #4. Download from The Crackme Website.
The Protection - This crackme has the standard name/serial protection. The serial is tested against a generated value that is calculated from the name.
The Required Tools - I used NuMega Softice, the debugger of all debuggers. You could use W32Dasm, but I don't recommend it. Also, as per usual, a brain and an open mind are required.
The Greetz - Many thanks to those who take the time to write the crackmes. Thanks to all people in #cracking4newbies and #win32asm. Greetz to StRAzOr, ACiD BuRN, Volatility, The Sandman, Fravia, +ORC, AlX, _Tribe and all other aspiring Crackerz!
Other Info - All S-ICE commands will be highlighted in RED. I will possibly use the following abbreviations:

- WTF = What the fuck?!
- HV = Hexadecimal valud
- ML = Memory Location
- SICE = Softice

This tutorial will (like the last one) focus on the ultimate solution - the Keygen. I will show those who wish to patch where/when/how, but will go on to show how to write the keygen for this crackme. It is a relatively simple algo, but I think alot can be learned by Keygenning this baby (esp for new-newbies :)).

THE ESSAY
Righto people, lets fire up the crackme and see what we have. As already said we are dealing with a name/serial registration. Punch in your name and serial. For this crackme I will be using karnak and 19781205. Lets set a breakpoint in SICE that should let us enter the code at the point where the proggie gets the text from the edit controls on the screen. So BPX hmemcpy, coz thats pretty universal (I mean alot of apps use it). Go back to windows, and hit the 'Check' button. WHAT?! No break?? How come SICE didn't pop up? Hmm... guess this aint using hmemcpy. So what do we do? Lets try an API call. To shorten this considerably, I'll just tell you that GetDlgItemText/GetDlgItemTextA don't work, neither do the SendMessage/SendMessageA routines, or even GetWindowText/GetWindowTextA. The actual routine that this program uses is the SendDlgItemMessageA. So lets BPX SendDlgItemMessageA, and go and press that 'Check' button once again. BINGO!! Now we're talkin!

Righto, press F11 to return from the function call and well have a look at some of the code. This is what I could see:

	
	:00401127  6A00                PUSH      00
	:00401129  6A00                PUSH      00
	:0040112B  6A0E                PUSH      0E
	:0040112D  6A03                PUSH      03
	:0040112F  FF7508              PUSH      DWORD PTR [EBP+08]
	:00401132  E841020000          CALL      USER32!SendDlgItemMessageA <--- Function call
	:00401137  A3AF214000          MOV       [004021AF],EAX             <--- We are here
	:0040113C  83F800              CMP       EAX,00
	:0040113F  0F84D5000000        JZ        0040121A
	:00401145  83F808              CMP       EAX,08
	:00401148  0F8FCC000000        JG        0040121A
	:0040114E  8BF0                MOV       ESI,EAX
	:00401150  6A00                PUSH      00
	:00401152  6A00                PUSH      00
	:00401154  6A0E                PUSH      0E
	:00401156  6A04                PUSH      04
	:00401158  FF7508              PUSH      DWORD PTR [EBP+08]
	:0040115B  E818020000          CALL      USER32!SendDlgItemMessageA <--- Function call
	:00401160  83F800              CMP       EAX,00
	:00401163  0F84B1000000        JZ        0040121A
	:00401169  3BF0                CMP       ESI,EAX
	:0040116B  0F85A9000000        JNZ       0040121A
	:00401171  6860214000          PUSH      00402160
	:00401176  6A08                PUSH      08
	:00401178  6A0D                PUSH      0D
	:0040117A  6A03                PUSH      03
	:0040117C  FF7508              PUSH      DWORD PTR [EBP+08]
	:0040117F  E8F4010000          CALL      USER32!SendDlgItemMessageA <--- Function call
	:00401184  6879214000          PUSH      00402179
	:00401189  6A10                PUSH      10
	:0040118B  6A0D                PUSH      0D
	:0040118D  6A04                PUSH      04
	:0040118F  FF7508              PUSH      DWORD PTR [EBP+08]
	:00401192  E8E1010000          CALL      USER32!SendDlgItemMessageA <--- Function call
OK we can see here that we are calling this function 4 times. Thats interesting, since we only have 2 controls. Anyway take a look at the first function call. One of the paramters to this call is 0E. This is the equivalent to the WM_GETTEXTLENGTH message in windows. So here we are finding the length of the text in one of the controls. Which one? Well, the return value is in EAX, and my contains 00000006 which tells me that it is referring to the name. We are then comparing this to 0 and 8. So in other words, we are jumping to the message box routine (ie 0040121A) if the length of the text is less that one, or greater than 8. After this, we then use the same function with the same 0E parameter to get the length of the serial number. This length is compared to the length of the name, if they aren't the same, then piss off. So at this point we'll have to go and shorten the serial number to make this loop work for us. I shortened mine to 197812. OK, now we've done the first couple of tests to make sure the name/serial combo COULD be ok, we then use the same routine, this time with the 0D parameter, which is the same as the WM_GETTEXT message. So we are storing the 2 values in memory somewhere, and continue on to the next peice of code, which looks like this:
	
	:00401197  B9FFFFFFFF          MOV       ECX,FFFFFFFF
	:0040119C  41                  INC       ECX
	:0040119D  0FBE8160214000      MOVSX     EAX,BYTE PTR [ECX+00402160]
	:004011A4  83F800              CMP       EAX,00
	:004011A7  7432                JZ        004011DB
	:004011A9  BEFFFFFFFF          MOV       ESI,FFFFFFFF
	:004011AE  83F841              CMP       EAX,41
	:004011B1  7C67                JL        0040121A
	:004011B3  83F87A              CMP       EAX,7A
	:004011B6  7762                JA        0040121A
	:004011B8  83F85A              CMP       EAX,5A
	:004011BB  7C03                JL        004011C0
	:004011BD  83E820              SUB       EAX,20
	:004011C0  46                  INC       ESI
	:004011C1  0FBE9617204000      MOVSX     EDX,BYTE PTR [ESI+00402017]
	:004011C8  3BC2                CMP       EAX,EDX
	:004011CA  75F4                JNZ       004011C0
	:004011CC  0FBE863C204000      MOVSX     EAX,BYTE PTR [ESI+0040203C]
	:004011D3  898194214000        MOV       [ECX+00402194],EAX
	:004011D9  EBC1                JMP       0040119C
	:004011DB  FF35AF214000        PUSH      DWORD PTR [004021AF]
	:004011E1  6894214000          PUSH      00402194
	:004011E6  6879214000          PUSH      00402179
	:004011EB  E854000000          CALL      00401244                   <--- Intersting
	:004011F0  83F801              CMP       EAX,01
	:004011F3  0F84DEFEFFFF        JZ        004010D7
	:004011F9  EB1F                JMP       0040121A
OK, after stepping over the first few lines of code, we can see that the proggie is checking to see if the characters that have been entered into the name field are valid characters. If they are, it converts them to uppercase (letter = letter - 20h) if they are lowercase. OK, after doing that, we seem to be comparing each letter of our name to some secret magic letter. At this point, to find out what we are comparing things to type DD 00402017. You should get a nice long string in your data window looking like this:

A1LSK2DJF4HGP3QWO5EIR6UTYZ8MXN7CBV9

So whats going on? Well, for each character in our name we're looping through this string to find a match for the letter. So my first match is at the 5th letter 'K'. This number is then used in another magic string. To have a look at this magic string type DD 0040203C, and you will see this:

SU7CSJKF09NCSDO0SDF09SDRLVK7809S4NF

So the 5th charactor of this string is 'S'. That is the first value I get. OK, we are looping through the whole name, so after the loop, my string looks like this:

SS90SS

Hmm, this is interesting... could this be my serial number? Well, lets have a look. After the loop has finished, and we have our string, we CALL 00401244, and then test a value. If this value is 1 then we have a valid key and we go somewhere, if its not 1 we go to the same 'BAD' messagebox at 0040121A. So after this function call we want EAX to be equal to 01h.

Lets check out the code in the function call. It looks like this:

	:00401244  C8000000            ENTER     0000,00
	:00401248  B801000000          MOV       EAX,00000001
	:0040124D  8B7D08              MOV       EDI,[EBP+08]
	:00401250  8B750C              MOV       ESI,[EBP+0C]
	:00401253  8B4D10              MOV       ECX,[EBP+10]
	:00401256  F3A6                REPZ CMPSB
	:00401258  67E305              JCXZ      00401260
	:0040125B  B800000000          MOV       EAX,00000000
	:00401260  C9                  LEAVE
	:00401261  C20C00              RET       000C
This is just a comparing function! We loop through the string we've created test each value with the corresponding value of the serial. At the start of the function we set EAX to 1. We want it to stay this way for the test after the function. So if the serial and the generated string is the same, the we leave, otherwise we set EAX to 0 and then leave.

So lets go back to our app and punch in our serial that the program generated for us, in my case its SS90SS.

Well done! Program registered!

THE KEYGEN
Easy keygen this one. Just create an algo that will receive as input a 1 - 8 character name, convert the name to UPPERcase, and use the 2 magic strings as a map to get the generated value. Pretty damn easy!!

Here is a PSUEDO-like example:

GetName();
if (NameLength > 0 and NameLength < 9)
{
ForEachCharInName
{
GetCharPosInFirstString();
SerialChar = CharAtPosInSecondString();
}
}

THE END
Well thats it guys, hope you learned something from this essay! Please drop me a line at karnak@apexmail.com if you need any help, or would like to see the source to my keygen.